import org.newdawn.slick.*;
import org.newdawn.slick.util.*;
import org.newdawn.slick.gui.*;

import java.util.*;

public class LobbyState implements ApplicationState {

	public static final int HOST = 0;
	public static final int LIST = 1;

	public static final int AUTO_REFRESH_LIST_INTERVAL = 20000;

	private static final int RIGHTCOL_X = 670;
	private static final int RIGHTCOL_SIZE = 32;
	private static final int RIGHTCOL_DOWN_Y = 328;
	private static final int RIGHTCOL_UP_Y = 286;
	private static final int RIGHTCOL_REFRESH_Y = 50;

	private int mouseX;
	private int mouseY;
	private int mouseDoubleClickTime;

	private int focused;
	private int selected;

	private int scroll;

	private ApplicationStateManager stateMan;

	private TextField playerName;
	private TextField serverName;
	private TextField numPlayers;
	private TextField gameName;
	private TextField gameNick;
	private Checkbox privateGame;
	private Checkbox allowObservers;

	private GameContainer container;

	private int mode;

	private int firstItemY[] = new int[2];
	private int itemSpacing[] = new int[2];

	private Image[][] lobbyGfx;

	private boolean shift;

	private String[] serverList = {};//{"MyServer","YourServer","Tetris!!11","Test","Lalalalala","Jaha","MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM","Ah","uhfes","usofhd","ushdf","isduf","idsfu"};
	private boolean[] serverStarted = {};

	private String centralServerStatus = "Idle";
	private int nextRefresh = 0;

	/**
	* Constructor for LobbyState.
	*
	* @param manager The ApplicationStateManager controlling this instance.
	*/
	public LobbyState(ApplicationStateManager manager, GameContainer cont) {
		stateMan = manager;
		container = cont;

		int xShift = 200;
		playerName = new LobbyTextField("Player name", container, Multitris.FONT1, xShift,100,300,24,this);
		playerName.setMaxLength(16);
		if (Multitris.startLocalName != null) {
			playerName.setText(Multitris.startLocalName);
		}
		serverName = new LobbyTextField("Server name",container, Multitris.FONT1, xShift,150,300,24,this);
		serverName.setMaxLength(32);
		numPlayers = new LobbyTextField("Max players",container, Multitris.FONT1, xShift,200,300,24,this);
		numPlayers.setMaxLength(2);
		numPlayers.setText("99");
		lobbyGfx = Multitris.lobbyHost;
		privateGame = new Checkbox("Private game?", xShift+300-22, 200+49, Multitris.FONT1, lobbyGfx[Multitris.LOBBY_HOST_PRIVATE][0], lobbyGfx[Multitris.LOBBY_HOST_PRIVATE][1], lobbyGfx[Multitris.LOBBY_HOST_PRIVATE][2], lobbyGfx[Multitris.LOBBY_HOST_PRIVATE][3], false, this);
		allowObservers = new Checkbox("Always open for observers?", xShift+300-22, 200+79, Multitris.FONT1, lobbyGfx[Multitris.LOBBY_HOST_OBSERVERS][0], lobbyGfx[Multitris.LOBBY_HOST_OBSERVERS][1], lobbyGfx[Multitris.LOBBY_HOST_OBSERVERS][2], lobbyGfx[Multitris.LOBBY_HOST_OBSERVERS][3], true, this);

		xShift = 100;
		gameName = new LobbyTextField("Game name",container, Multitris.FONT1, xShift, 370, 500,24,this);

		gameNick = new LobbyTextField("Player name",container, Multitris.FONT1, xShift, 400, 500,24,this);
		gameNick.setText("Default");
		if (Multitris.startLocalName != null) {
			gameNick.setText(Multitris.startLocalName);
		}
		gameNick.setCursorPos(gameNick.getText().length()-1);

		firstItemY[HOST] = 445;
		firstItemY[LIST] = 445;

		itemSpacing[HOST] = 70;
		itemSpacing[LIST] = 70;
	}


	/**
	* Informs the LobbyState that the mouse has been moved.
	*
	* @param oldx The old x coordinate.
	* @param oldy The old y coordinate.
	* @param newx The new x coordinate.
	* @param newy The new y coordinate.
	*/
	public void mouseMoved(int oldx, int oldy, int newx, int newy) {
		mouseX = newx;
		mouseY = newy;
		mouseDoubleClickTime = -1;

		int firstItem = 0;
		if(mode == HOST)
			firstItem = Multitris.LOBBY_HOST_CREATE;
		if(mode == LIST)
			firstItem = Multitris.LOBBY_LIST_JOIN;

		int numItems = 0;
		if(mode == HOST)
			numItems = 2;
		if(mode == LIST)
			numItems = 2;

		if(mouseY > firstItemY[mode] && mouseY < firstItemY[mode]+itemSpacing[mode]*numItems) {
			focused = (mouseY-firstItemY[mode])/itemSpacing[mode]+firstItem;
		}

		boolean hoverRefresh = (mouseX >= RIGHTCOL_X && mouseX <= RIGHTCOL_X + RIGHTCOL_SIZE && mouseY >= RIGHTCOL_REFRESH_Y && mouseY <= RIGHTCOL_REFRESH_Y + RIGHTCOL_SIZE);
		if(hoverRefresh)
			focused = Multitris.LOBBY_LIST_REFRESH;

	}

	/**
	* Scrolls to the correct position in the game browser.
	*/
	private void scroll() {
		if (selected < scroll)
			scroll = selected;
		if (selected > scroll+9)
			scroll = selected-9;
		/*if(selected > 9)
			scroll = selected-9;
		else
			scroll = 0;*/
	}

	/**
	* Informs the LobbyState that a mouse button has been pressed.
	*
	* @param button The old mouse button pressed.
	* @param y The y coordinate.
	* @param x The x oordinate.
	*/
	public void mousePressed(int button, int x, int y) {
		boolean doubleClick = (mouseDoubleClickTime >= 0);
		if (doubleClick) {
			System.out.println("Double click noticed");
		}
		mouseX = x;
		mouseY = y;

		if(mode == HOST) {
			playerName.mousePressed(button, x, y);
			serverName.mousePressed(button, x, y);
			numPlayers.mousePressed(button, x, y);
			privateGame.mousePressed(button, x, y);
			allowObservers.mousePressed(button, x, y);

			//if(focused != Multitris.LOBBY_HOST_PRIVATE && focused != Multitris.LOBBY_HOST_PRIVATE && focused != Multitris.LOBBY_HOST_OBSERVERS)
			activateFocused();
		}

		if(mode == LIST) {
			if(mouseY > 50 && mouseY < 360 && mouseX >= 100 && mouseX <= 650) {
				selected = (mouseY-50)/30+scroll;
				focused = -1;
				if(selected > serverList.length-1)
					selected = 0;
				if(serverList.length >= 1) {
					gameName.setText(serverList[selected]);
					if (doubleClick) {
						focused = Multitris.LOBBY_LIST_JOIN;
						activateFocused();
					}
				}
				scroll();
			}

			if(mouseX >= RIGHTCOL_X && mouseX <= RIGHTCOL_X + RIGHTCOL_SIZE && mouseY >= RIGHTCOL_UP_Y && mouseY <= RIGHTCOL_UP_Y + RIGHTCOL_SIZE) {
				selected--;
				if(selected < 0) {
					selected = Math.max(serverList.length-1,0);
				}
				scroll();

			}

			if(mouseX >= RIGHTCOL_X && mouseX <= RIGHTCOL_X + RIGHTCOL_SIZE && mouseY >= RIGHTCOL_DOWN_Y && mouseY <= RIGHTCOL_DOWN_Y + RIGHTCOL_SIZE) {
				selected++;
				if(selected > serverList.length-1) {
					selected = 0;
				}
				scroll();
			}

			if(mouseX >= RIGHTCOL_X && mouseX <= RIGHTCOL_X + RIGHTCOL_SIZE && mouseY >= RIGHTCOL_REFRESH_Y && mouseY <= RIGHTCOL_REFRESH_Y + RIGHTCOL_SIZE) {
				refreshList();
			}

			gameName.mousePressed(button, x, y);
			gameNick.mousePressed(button, x, y);

			if(mouseY >= 360) {
				activateFocused();
			}
		}

		mouseDoubleClickTime = Multitris.DOUBLE_CLICK_TIME;
	}

	/**
	* Renders the LobbyState.
	*
	* @param g The graphics context to render to.
	*/
	public void render(Graphics g) {
		if(mode == HOST) {
			//g.setColor(Color.white);
			playerName.render(container, g);
			serverName.render(container, g);
			numPlayers.render(container, g);
			privateGame.render(g, focused == Multitris.LOBBY_HOST_PRIVATE);
			allowObservers.render(g, focused == Multitris.LOBBY_HOST_OBSERVERS);

			if(focused != Multitris.LOBBY_HOST_CREATE)
				g.drawImage(lobbyGfx[Multitris.LOBBY_HOST_CREATE][1], 400-lobbyGfx[Multitris.LOBBY_HOST_CREATE][0].getWidth()/2, firstItemY[HOST]);
			else
				g.drawImage(lobbyGfx[Multitris.LOBBY_HOST_CREATE][0], 400-lobbyGfx[Multitris.LOBBY_HOST_CREATE][0].getWidth()/2, firstItemY[HOST]);

			if(focused != Multitris.LOBBY_HOST_BACK)
				g.drawImage(lobbyGfx[Multitris.LOBBY_HOST_BACK][1], 400-lobbyGfx[Multitris.LOBBY_HOST_BACK][0].getWidth()/2, firstItemY[HOST]+itemSpacing[HOST]);
			else
				g.drawImage(lobbyGfx[Multitris.LOBBY_HOST_BACK][0], 400-lobbyGfx[Multitris.LOBBY_HOST_BACK][0].getWidth()/2, firstItemY[HOST]+itemSpacing[HOST]);

		}
		if(mode == LIST) {

			int hover;

			hover = (mouseX >= RIGHTCOL_X && mouseX <= RIGHTCOL_X + RIGHTCOL_SIZE && mouseY >= RIGHTCOL_UP_Y && mouseY <= RIGHTCOL_UP_Y + RIGHTCOL_SIZE ? 1 : 0);
			g.drawImage(lobbyGfx[Multitris.LOBBY_LIST_ARROWUP][hover],RIGHTCOL_X,RIGHTCOL_UP_Y);

			hover = (mouseX >= RIGHTCOL_X && mouseX <= RIGHTCOL_X + RIGHTCOL_SIZE && mouseY >= RIGHTCOL_DOWN_Y && mouseY <= RIGHTCOL_DOWN_Y + RIGHTCOL_SIZE ? 1 : 0);
			g.drawImage(lobbyGfx[Multitris.LOBBY_LIST_ARROWDOWN][hover],RIGHTCOL_X,RIGHTCOL_DOWN_Y);

			int focusedRefresh = (focused == Multitris.LOBBY_LIST_REFRESH ? 1 : 0);
			g.drawImage(lobbyGfx[Multitris.LOBBY_LIST_REFRESH][focusedRefresh],RIGHTCOL_X,RIGHTCOL_REFRESH_Y);

			/*if(focused == Multitris.LOBBY_LIST_GAMENAME-1) {
				g.setColor(new Color(34, 34, 34));
				g.fillRect(100,50,560,310);
			}

			g.setColor(Color.white);
			g.drawRect(100,50,560,310);
			*/

			g.setColor(new Color(0,10,30));
			g.fillRoundRect(100,50,560,310,6);
			g.setColor(new Color(50,100,200));
			g.setAntiAlias(true);
			g.drawRoundRect(100,50,560,310,6);
			g.setAntiAlias(false);

			g.setColor(new Color(255,255,255));

			g.setFont(Multitris.FONT1);
			if (scroll < 0) scroll = 0;
			for(int i=0; i<10; i++) {
				if(i+scroll < serverList.length) {
					if(selected == i+scroll) {
						//g.setColor(new Color(10, 26, 51));
						g.setColor(new Color(10, 25, 70));
						g.fillRect(101,55+30*i,558,30);
						//g.setColor(new Color(34, 68, 136));
						g.setColor(new Color(50, 80, 170));
						//g.setColor(new Color(180,180,180));
						//g.setColor(new Color(0,0,0));
						g.drawLine(101,58+30*i,658,58+30*i);
						g.drawLine(101,83+30*i,658,83+30*i);
					}
					if (serverStarted[i+scroll]) {
						//g.setColor(Color.yellow);
						g.setColor(Color.white);
					} else {
						g.setColor(Color.white);
					}
					g.drawString(serverList[i+scroll] + (serverStarted[i+scroll] ? " (in-game)" : ""), 110, 60+30*i);
				}
			}

			g.drawString("Status: " + centralServerStatus, 100, 20);

			gameName.render(container, g);
			gameNick.render(container, g);

			if(focused != Multitris.LOBBY_LIST_JOIN)
				g.drawImage(lobbyGfx[Multitris.LOBBY_LIST_JOIN][1], 400-lobbyGfx[Multitris.LOBBY_LIST_JOIN][0].getWidth()/2, firstItemY[LIST]);
			else
				g.drawImage(lobbyGfx[Multitris.LOBBY_LIST_JOIN][0], 400-lobbyGfx[Multitris.LOBBY_LIST_JOIN][0].getWidth()/2, firstItemY[LIST]);

			if(focused != Multitris.LOBBY_LIST_BACK)
				g.drawImage(lobbyGfx[Multitris.LOBBY_LIST_BACK][1], 400-lobbyGfx[Multitris.LOBBY_LIST_BACK][0].getWidth()/2, firstItemY[LIST]+itemSpacing[LIST]);
			else
				g.drawImage(lobbyGfx[Multitris.LOBBY_LIST_BACK][0], 400-lobbyGfx[Multitris.LOBBY_LIST_BACK][0].getWidth()/2, firstItemY[LIST]+itemSpacing[LIST]);

		}




	}

	/**
	* Updates the LobbyState.
	*
	* @param delta The time passed since the last call to update.
	*/
	public void update(int delta) {
		if(mode == HOST) {
			playerName.setBackgroundColor(Color.black);
			serverName.setBackgroundColor(Color.black);
			numPlayers.setBackgroundColor(Color.black);

			if(focused == Multitris.LOBBY_HOST_PLAYERNAME) {
				playerName.setFocus(true);
				playerName.setBackgroundColor(new Color(0x222222));
			}
			else if(focused == Multitris.LOBBY_HOST_SERVERNAME) {
				serverName.setFocus(true);
				serverName.setBackgroundColor(new Color(0x222222));
			}
			else if(focused == Multitris.LOBBY_HOST_NUMPLAYERS) {
				numPlayers.setFocus(true);
				numPlayers.setBackgroundColor(new Color(0x222222));
			} else {
				playerName.setFocus(false);
				serverName.setFocus(false);
				numPlayers.setFocus(false);
			}
		}
		if(mode == LIST) {
			mouseDoubleClickTime -= delta;
			if ((nextRefresh -= delta) <= 0) {
				refreshList();
			}

			gameName.setBackgroundColor(Color.black);
			gameNick.setBackgroundColor(Color.black);

			if(focused == Multitris.LOBBY_LIST_GAMENAME) {
				gameName.setFocus(true);
				gameName.setBackgroundColor(new Color(0x222222));
			} else if (focused == Multitris.LOBBY_LIST_GAMENICK) {
				gameNick.setFocus(true);
				gameNick.setBackgroundColor(new Color(0x222222));
			} else {
				gameName.setFocus(false);
				gameNick.setFocus(false);
			}
			if(focused != Multitris.LOBBY_LIST_GAMENICK && gameNick.getText().equals("")) {
				gameNick.setText("Default");
				gameNick.setCursorPos(gameNick.getText().length()-1);
			}
			if(focused == Multitris.LOBBY_LIST_GAMENICK && gameNick.getText().equals("Default")) {
				gameNick.setText("");
				gameNick.setCursorPos(0);
			}

			LinkedList<String[]> servers = Multitris.clientCommunication.getServerList();
			if (servers != null) { // a request have been fulfilled
				serverList = new String[servers.size()];
				serverStarted = new boolean[servers.size()];
				int i=0;
				for (String[] parts : servers) {
					serverStarted[i] = parts[2].equals("1"); // is server already started
					if (parts.length == 4) {
						serverList[i] = parts[3]; // the server name
					} else {
						serverList[i] = "Unnamned";
					}
					i++;
				}
				centralServerStatus = "Idle";

				if (serverList.length > 0 && gameName.getText().equals("") && selected <= serverList.length) {
					gameName.setText(serverList[selected]);
				}
			}
		}
	}

	/**
	* Sets a mode for the state.
	*
	* @param parameter the mode to set.
	*/
	public void setMode(Object parameter) {
		mode = (Integer)parameter;

		// When this state is switched to, reset the focus.
		if(mode == HOST) {
			focused = Multitris.LOBBY_HOST_PLAYERNAME;
			lobbyGfx = Multitris.lobbyHost;
		}
		if(mode == LIST) {
			focused = Multitris.LOBBY_LIST_GAMENAME-1;
			lobbyGfx = Multitris.lobbyList;
			selected = 0;
			scroll = 0;
			serverList = new String[0];
			serverStarted = new boolean[0];
			if(serverList.length >= 1)
				gameName.setText(serverList[selected]);

			Multitris.clientCommunication.requestServerList();
		}
	}

	/**
	* Focuses the given LobbyTextField;
	*
	* @param tf The LobbyTextField to focus.
	*/
	public void focusField(LobbyTextField tf) {
		if(mode == HOST) {
			if(tf.equals(playerName)) {
				focused = Multitris.LOBBY_HOST_PLAYERNAME;
			}
			if(tf.equals(serverName)) {
				focused = Multitris.LOBBY_HOST_SERVERNAME;
			}
			if(tf.equals(numPlayers)) {
				focused = Multitris.LOBBY_HOST_NUMPLAYERS;
			}
		}
		if(mode == LIST) {
			if(tf.equals(gameName)) {
				focused = Multitris.LOBBY_LIST_GAMENAME;
			}
			if(tf.equals(gameNick)) {
				focused = Multitris.LOBBY_LIST_GAMENICK;
			}
		}
	}

	/**
	* Focuses the given Checkbox;
	*
	* @param c The Checkbox to focus.
	*/
	public void focusBox(Checkbox c) {
		if(mode == HOST) {
			if(c.equals(privateGame)) {
				focused = Multitris.LOBBY_HOST_PRIVATE;
			}
			if(c.equals(allowObservers)) {
				focused = Multitris.LOBBY_HOST_OBSERVERS;
			}
		}
	}

	/**
	* Informs the LobbyState that an action has been requested.
	*
	* @param action The action requested.
	*/
	public void doInputAction(String action) {

		if(action.equals("p_shift")) {
			shift = true;
		}
		if(action.equals("r_shift")) {
			shift = false;
		}

		if(mode == HOST) {
			if(action.equals("p_up") || (action.equals("p_tab") && shift)) {
				focused--;
				if(focused < Multitris.LOBBY_HOST_PLAYERNAME)
					focused = Multitris.LOBBY_HOST_BACK;
			}
			if(action.equals("p_down") || (action.equals("p_tab") && !shift)) {
				focused++;
				if(focused > Multitris.LOBBY_HOST_BACK)
					focused = Multitris.LOBBY_HOST_PLAYERNAME;
			}
		}
		if(mode == LIST) {
			if((action.equals("p_tab") && shift)) {
				focused--;
				if(focused < Multitris.LOBBY_LIST_GAMENAME-1)
					focused = Multitris.LOBBY_LIST_REFRESH;
			}
			if((action.equals("p_tab") && !shift)) {
				focused++;
				if(focused > Multitris.LOBBY_LIST_REFRESH)
					focused = Multitris.LOBBY_LIST_GAMENAME-1;
			}
			if(action.equals("p_up")) {
				if(focused == Multitris.LOBBY_LIST_GAMENAME-1) {
					selected--;
					if(selected < 0) {
						selected = Math.max(serverList.length-1,0);
					}
					if(serverList.length >= 1)
						gameName.setText(serverList[selected]);
				}
				else {
					focused--;
					if(focused < Multitris.LOBBY_LIST_GAMENAME) {
						selected = serverList.length-1;
						if(serverList.length >= 1)
							gameName.setText(serverList[selected]);
					}
				}
				scroll();
			}
			if(action.equals("p_down")) {
				if(focused == Multitris.LOBBY_LIST_GAMENAME-1) {
					selected++;
					if(selected > serverList.length-1) {
						selected = 0;
					}
					if(serverList.length >= 1)
						gameName.setText(serverList[selected]);
				}
				else {
					focused++;
					if(focused > Multitris.LOBBY_LIST_BACK) {
						focused = Multitris.LOBBY_LIST_GAMENAME-1;
						selected = 0;
						if(serverList.length >= 1)
							gameName.setText(serverList[selected]);
					}
				}
				scroll();
			}
			System.out.println("scroll: "+scroll);
		}

		if(action.startsWith("p_use")) {
			activateFocused();
		}
		if(action.equals("p_cancel")) {
			if(mode == HOST) {
				focused = Multitris.LOBBY_HOST_BACK;
			}
			if(mode == LIST) {
				focused = Multitris.LOBBY_LIST_BACK;
			}
			activateFocused();
		}
	}

	private void refreshList() {
		Multitris.clientCommunication.requestServerList();
		serverList = new String[0];
		serverStarted = new boolean[0];

		centralServerStatus = "Waiting for central server response";
		nextRefresh = AUTO_REFRESH_LIST_INTERVAL;
	}

	private void activateFocused() {
		if(mode == HOST) {
			if(focused == Multitris.LOBBY_HOST_BACK) {
				playerName.setFocus(false);
				serverName.setFocus(false);
				numPlayers.setFocus(false);
				stateMan.switchState(ApplicationStateManager.MENU);
			}
			if(focused == Multitris.LOBBY_HOST_PRIVATE)
				privateGame.switchState();
			if(focused == Multitris.LOBBY_HOST_OBSERVERS)
				allowObservers.switchState();
			if(focused == Multitris.LOBBY_HOST_CREATE) {
				System.out.println("Hosting game");
				ArrayList<Object> list = new ArrayList<Object>();
				list.add(0); // host mode
				list.add(playerName.getText());
				list.add(serverName.getText());
				list.add(Integer.parseInt(numPlayers.getText()));
				list.add(privateGame.getState());
				list.add(allowObservers.getState());
				stateMan.switchState(ApplicationStateManager.CHAT, list);
			}
		}
		if(mode == LIST) {
			if(focused == Multitris.LOBBY_LIST_JOIN || focused == -1) { // -1 = server list
				if (!gameName.getText().equals("")) {
					System.out.println("Joining game");
					ArrayList<Object> list = new ArrayList<Object>();
					list.add(1); // join mode
					String name = gameNick.getText();
					if(name == null || name.equals("")) {
						name = "Client"+(int)(Math.random()*1000);
					}
					list.add(name);
					list.add(gameName.getText());
					gameName.setFocus(false);
					gameNick.setFocus(false);
					stateMan.switchState(ApplicationStateManager.CHAT, list);
				}
			}
			if(focused == Multitris.LOBBY_LIST_REFRESH) {
				refreshList();
			}
			if(focused == Multitris.LOBBY_LIST_BACK) {
				gameName.setFocus(false);
				stateMan.switchState(ApplicationStateManager.MENU);
			}
		}
	}
}